package com.xm.servlet.reception_desk.pay;

import com.xm.exception.SqlErrorException;
import com.xm.service.reception_desk.OrdersService;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;

import javax.servlet.AsyncContext;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 计算订单到期时间
 * @author 康文程
 * @date 2024-1-10 上午 07:57
 */
@WebServlet(urlPatterns = "/order/expires/date", asyncSupported = true)
public class OrderExpiresDateServlet extends HttpServlet {
    /**
     * 订单ordersService
     */
    private final OrdersService ordersService = new OrdersService();

    /** 为什么不能手动创建线程，而选择使用ThreadPoolExecutor自定义线程队列
     * 1.线程的创建和销毁消耗大量的系统资源，而线程池可以重复利用线程，从而减少了这种开销。
     * 2.如果同时创建大量线程，可能会导致系统内存不足，从而引发OutOfMemoryError异常。
     * 3.如果线程没有合理的调度，可能会导致线程饥饿和死锁等问题。
     * 核心线程数为10，最大线程数为100，空闲线程存活时间为60秒.可以避免线程饥饿和死锁等问题
     * 线程池
     * corePoolSize 核心线程数
     * maximumPoolSize 最大线程数
     * keepAliveTime 空闲线程存活时间
     * 存活时间单位
     * 任务队列
     * 自定义ThreadFactory
     * 线程池 不应该手动去创建线程池
     * private final ExecutorService threadPool = Executors.newFixedThreadPool(10);
     * 注意 : 在Servlet中，由于请求的处理时间不确定，如果使用手动创建线程来处理请求，可能会出现以下问题：
     * 如果并发请求数量过多，可能会导致线程池过度消耗系统资源，从而影响整个系统的性能。
     * 如果线程没有及时回收，可能会导致内存泄漏，从而导致系统崩溃。
     * 如果线程没有正确的调度，可能会导致一些请求长时间得不到响应，从而影响用户体验。
     */
    private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            10,
            100,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            new NamedThreadFactory("OrderExpiresDateThread")
    );
    /**
     * 处理GET请求
     */
    @SneakyThrows
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        // 设置响应头
        resp.setContentType("text/html;charset=utf-8");

        // 获取订单ID
        String orderId = req.getParameter("orderId");

        // 开始异步处理请求
        AsyncContext context = req.startAsync();
        threadPool.submit(() -> {
            try {
                // 处理业务逻辑
                int orderExpirationTimeByAddressId = ordersService.getOrderExpirationTimeByOrderId(orderId);
                System.out.println(orderExpirationTimeByAddressId);
                // 发送响应数据
                resp.getWriter().println(orderExpirationTimeByAddressId);

                // 完成异步处理
                context.complete();
            } catch (IOException | SqlErrorException e) {
                e.printStackTrace();
            }
        });
    }
    /**
     * 关闭线程池
     */
    @Override
    public void destroy() {
        // 关闭线程池
        threadPool.shutdown();
        super.destroy();
    }

    /**
     * 自定义ThreadFactory，用于指定有意义的线程名称
     */
    private static class NamedThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger count = new AtomicInteger(1);

        public NamedThreadFactory(String namePrefix) {
            this.namePrefix = namePrefix;
        }

        @Override
        public Thread newThread(@NotNull Runnable r) {
            Thread t = new Thread(r);
            t.setName(namePrefix + "-" + count.getAndIncrement());
            return t;
        }
    }
}